using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using Banshee.Base;
using Banshee.Database;
using Banshee.Sources;


namespace Banshee.Base.Gui
{
    public class SourceView:TreeView
    {
        private Source newPlaylistSource = new PlaylistSource(-1);
        private bool newPlaylistVisible = false;
        private int currentTimeout = -1;
        string name_format = "{0} ({1})";
        public SourceView()
        {
            SetStyle(ControlStyles.OptimizedDoubleBuffer | ControlStyles.AllPaintingInWmPaint, true);
            UpdateStyles();
            CreateMenu();
            CreateContextMenu();
            CreateNodeMenu();
            imglist = new ImageList();
            imglist.Images.Add(IconThemeUtils.LoadIcon(ConfigureDefines.ICON_THEME_DIR+@"\user-home.png"));
            this.ImageList = imglist;
            AddSource(SourceManager.DefaultSource);
            SourceManager.SourceAdded += new SourceAddedHandler(SourceManager_SourceAdded);
            SourceManager.SourceRemoved += new SourceEventHandler(SourceManager_SourceRemoved);
            MouseHover += new EventHandler(SourceView_MouseHover);
            this.DragEnter += new DragEventHandler(SourceView_DragEnter);
            this.DragDrop += new DragEventHandler(SourceView_DragDrop);
            this.NodeMouseHover += new TreeNodeMouseHoverEventHandler(SourceView_NodeMouseHover);
            this.AfterLabelEdit += new NodeLabelEditEventHandler(SourceView_AfterLabelEdit);
            this.MouseDown += new MouseEventHandler(SourceView_MouseDown);
            LabelEdit = false;
            this.AllowDrop = true;
            this.ShowLines = false;
            this.MouseDoubleClick += new MouseEventHandler(SourceView_MouseDoubleClick);
        }

        void SourceView_MouseDown(object sender, MouseEventArgs e)
        {
            selected_node = GetNodeAt(e.X, e.Y);
        }

        void SourceView_NodeMouseHover(object sender, TreeNodeMouseHoverEventArgs e)
        {
            selected_node = e.Node;
        }

        void SourceView_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            TreeNode node = GetNodeAt(e.X, e.Y);
            Source source = node.Tag as Source;
            SourceManager.SetActiveSource(source, true);
            SelectedNode = node;
        }
        TreeNode selected_node;
        void SourceView_MouseHover(object sender, EventArgs e)
        {

            Point clientPoint = PointToClient(new Point(MousePosition.X, MousePosition.Y));
            TreeNode node = this.GetNodeAt(clientPoint);
            if (node != null)
                selected_node = node;
        }
        private TrackInfo track_ToAdd;

        public TrackInfo TrackToAdd
        {
            get { return track_ToAdd; }
            set { track_ToAdd = value; }
        }
        string source_name(string text)
        {
            string[] result = text.Split('(');
            return result[0];
        }
        TrackInfo PathTreeInfo(string path)
        {
            TrackInfo pathtrackinfo = null;
            foreach (TrackInfo track in SourceManager.ActiveSource.Tracks)
            {
                if (track.Uri.ToString() == path)
                {
                    pathtrackinfo = track;
                    break;
                }
            }
            return pathtrackinfo;
        }
        DataGridViewSelectedRowCollection drows;

        public DataGridViewSelectedRowCollection DragRows
        {
            get { return drows; }
            set { drows = value; }
        }
        void SourceView_DragDrop(object sender, DragEventArgs e)
        {
            Point clientPoint = PointToClient(new Point(e.X, e.Y));
            //Cornel this is horrible hack
            selected_node = GetNodeAt(clientPoint);
            this.SelectedNode = selected_node;
            PlaylistSource newPlaylist = null;
            List<TrackInfo> tracks = new List<TrackInfo>();
            for (int i = 0; i < drows.Count; i++)
            {
                TrackInfo track = PathTreeInfo(drows[i].Cells[10].Value.ToString());
                tracks.Add(track);
            }

            Source source = null;
            if(selected_node != null)
            source = selected_node.Tag as Source; 
            if (source == null)
            {
                source = newPlaylistSource;
            }
                

                newPlaylist = null;

                if (source.GetType() == typeof(LibrarySource) && SourceManager.ActiveSource is IImportable)
                {
                    IImportable import_source = SourceManager.ActiveSource as IImportable;

                    import_source.Import(tracks);
                }
                else if (source.GetType() == typeof(PlaylistSource) && SourceManager.ActiveSource is IImportable)
                {
                    IImportable import_source = SourceManager.ActiveSource as IImportable;
                    PlaylistSource playlist = null;

                    if (source == newPlaylistSource)
                    {
                        playlist = new PlaylistSource();
                        LibrarySource.Instance.AddChildSource(playlist);
                        newPlaylist = playlist;
                    }
                    else
                    {
                        playlist = source as PlaylistSource;
                    }

                    import_source.Import(tracks, playlist);
                }
                else if (source == newPlaylistSource)
                {
                    PlaylistSource playlist = new PlaylistSource();
                    playlist.AddTrack(tracks);
                    playlist.Rename(Banshee.Sources.PlaylistSource.PlaylistUtil.GoodUniqueName(playlist.Tracks));
                    playlist.Commit();
                    AddSource(playlist,0,Nodes[0]);
                    //LibrarySource.Instance.AddChildSource(playlist);
                    UpdateView();
                }
                else if (source.GetType() == typeof(PlaylistSource) || source.AcceptsInput)
                {
                    source.AddTrack(tracks);
                    source.Commit();
                }
                else if (source.GetType() == typeof(DapPlaylistSource) || source.GetType() == typeof(DapSource))
                {
                    source.AddTrack(tracks);
                    source.Commit();
                }
                int count = source.Count;
                string name = string.Format(name_format, source.Name, count);
                selected_node.Text = name;
                //RefreshList();
        }

        void SourceView_DragEnter(object sender, DragEventArgs e)
        {
             e.Effect = DragDropEffects.Copy;
             TreeNode node = GetNodeAt(e.X, e.Y);
             selected_node = node;
        }

        void SourceManager_SourceRemoved(SourceEventArgs args)
        {
            RemoveSource(args.Source);
        }

        void SourceManager_SourceAdded(SourceAddedArgs args)
        {
            AddSource(args.Source, args.Position);
        }
        bool refreshing = false;
        public void RefreshList()
        {
            if (this.InvokeRequired)
                this.Invoke((MethodInvoker)delegate() { RefreshList(); });
            else
            {
                if (!refreshing)
                {
                    refreshing = true;
                    BeginUpdate();
                    Nodes.Clear();

                    foreach (Source source in SourceManager.Sources)
                    {
                        AddSource(source);
                    }
                    refreshing = false;
                    if (Nodes.Count > 0)
                    {
                        if (selected_node == null)
                            SelectedNode = Nodes[0];
                        else
                            SelectedNode = selected_node;
                    }
                    EndUpdate();
                }
            }
        }
        private void AddSource(Source source)
        {
            AddSource(source, Nodes.Count);
        }
        private void AddSource(Source source, int position)
        {

            if (source != null)
            {
                if (source.GetType() == typeof(PlaylistSource))
                {
                    if (this.Nodes.Count > 0)
                    {
                        AddSource(source, position, this.Nodes[0]);
                    }
                }
                else
                    AddSource(source, position, null);
            }
        }
        private void AddSource(Source source, int position, TreeNode parent)
        {
            if (source != null)
            {
                Icon ico = source.Icon;
                if (ico != null)
                {
                    ImageList.Images.Add(ico);
                }

                int count = source.Count;
                string name = string.Format(name_format, source.Name, count);
                if (parent == null)
                {
                    //this adds a new root node;
                    string.Format("{0} {1}", source.Name, source.Tracks);
                    TreeNode libnode = new TreeNode(name, 0, 0);
                    if (source.MenuStrip != null)
                        libnode.ContextMenuStrip = source.MenuStrip;
                    libnode.Tag = source;

                    this.Nodes.Add(libnode);
                    
                    source.Expanded = true;
                    libnode.Expand();
                    libnode.ImageIndex = imglist.Images.Count - 1;
                    libnode.SelectedImageIndex = imglist.Images.Count - 1; ;
                    return;
                }
                if (!FindSource(source).Equals(this.Nodes[0]))
                    return;

                TreeNode newnode = new TreeNode();

                newnode.Text = name;
                if (imglist.Images.Count > 0)
                {
                    newnode.ImageIndex = imglist.Images.Count - 1;

                    newnode.SelectedImageIndex = imglist.Images.Count - 1;
                }
                if (parent == this.Nodes[0])
                    parent.Nodes.Add(newnode);
                else
                    Nodes.Add(newnode);
                lock (source.Children)
                {
                    foreach (ChildSource s in source.Children)
                    {
                        AddSource(s, position, newnode);
                    }
                }
                source.ChildSourceAdded += delegate(SourceEventArgs e)
                {
                    AddSource(e.Source, position, newnode);
                };

                source.ChildSourceRemoved += delegate(SourceEventArgs e)
                {
                    RemoveSource(e.Source);
                };
                if (source.Expanded || (source.AutoExpand != null && source.AutoExpand.Value))
                {
                    newnode.Expand();
                }
                source.TrackAdded += new TrackEventHandler(source_TrackAdded);

                if (source.MenuStrip != null)
                    newnode.ContextMenuStrip = source.MenuStrip;
                else 
                    newnode.ContextMenuStrip = node_menu_strip;
                
                newnode.Tag = source;
                UpdateView();
            }
        }

        ContextMenuStrip node_menu_strip;
        
        void CreateNodeMenu()
        {
            node_menu_strip = new ContextMenuStrip();
            ToolStripMenuItem node_edit_item = new ToolStripMenuItem("Rename Playlist");
            node_edit_item.Click += new EventHandler(node_edit_item_Click);
            ToolStripMenuItem node_remove_item = new ToolStripMenuItem("Delete Playlist");
            node_remove_item.Click += new EventHandler(node_remove_item_Click);
            ToolStripMenuItem node_clear = new ToolStripMenuItem("Clear");
            node_menu_strip.Items.Add(new ToolStripSeparator());
            node_clear.Click += new EventHandler(node_clear_Click);
            node_menu_strip.Items.Add(node_edit_item);
            node_menu_strip.Items.Add(node_remove_item);
            //node_menu_strip.Items.Add(node_clear);
        }

        void node_clear_Click(object sender, EventArgs e)
        {
            DialogResult dr = MessageBox.Show("Are you sure you want to clear this playlist?", "Clear", MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
            if (dr == DialogResult.Yes)
            {
                TreeNode node = SelectedNode;
                Source source = node.Tag as Source;
                source.RemoveTrack(source.Tracks);
                source.Commit();
                RefreshList();
            }
        }

        void node_remove_item_Click(object sender, EventArgs e)
        {

            TreeNode node = SelectedNode;
            if (node != null)
            {
                Source source = node.Tag as Source;
                if (source.GetType() != typeof(Sources.LibrarySource))
                {
                    SourceManager.RemoveSource(source);
                    node.Remove();
                }
            }
            SourceManager.ActiveSource.Commit();
        }

        void node_edit_item_Click(object sender, EventArgs e)
        {

            LabelEdit = true;
            TreeNode node = SelectedNode;
            if (node != null && node.Parent != null)
            {
                if (!node.IsEditing)
                    node.BeginEdit();
            }
        }
        void SourceView_AfterLabelEdit(object sender, NodeLabelEditEventArgs e)
        {
            e.Node.EndEdit(false);
            string newtext = e.Label;
            Rename(e.Node,newtext);
            LabelEdit = false;
        }
        void Rename(TreeNode node,string newname)
        {
            Source source = node.Tag as Source;
            source.Rename(newname);
            int count = source.Count;
            string name = string.Format(name_format, source.Name, count);
            node.Text = name;
        }

        ContextMenu source_menu;
        MenuItem source_add_menu;
        void CreateContextMenu()
        {
            source_menu = new ContextMenu();
            source_add_menu = new MenuItem("Add Playlist");
            source_add_menu.Click += new EventHandler(source_add_menu_Click);
            source_menu.MenuItems.Add(source_add_menu);
        }

        void source_add_menu_Click(object sender, EventArgs e)
        {
            PlaylistSource pls = new PlaylistSource();
            int pos = Nodes[0].Nodes.Count+1;
            SourceManager.AddSource(pls);
            
        }
        ContextMenuStrip menu = null;

        void CreateMenu()
        {
            menu = new ContextMenuStrip();
            ToolStripMenuItem refresh_menu = new ToolStripMenuItem("Refresh Sources");
            refresh_menu.Click += new EventHandler(refresh_menu_Click);
            menu.Items.Add(refresh_menu);
            this.ContextMenuStrip = menu;
            
        }

        void refresh_menu_Click(object sender, EventArgs e)
        {
            RefreshList();
        }
        ImageList imglist;

        void source_TrackAdded(object o, TrackEventArgs args)
        {
            
        }
        private void RemoveSource(Source source)
        {
            UpdateView();
        }

        private bool UpdateView()
        {
            Nodes[0].Expand();
            return true;
        }
        private TreeNode FindSource(Source source)
        {
            TreeNode iter = this.Nodes[0];
            return FindSource(source, iter);
        }

        private TreeNode FindSource(Source source, TreeNode iter)
        {
            if (!this.Nodes.Contains(iter))
            {
                return this.Nodes[0];
            }

            TreeNode[] node = new TreeNode[1];
            node = this.Nodes.Find(iter.Name, true);

            return node[0];
        }
    }
}
